#include <utility> // std::swap
#include <iostream>

class shared_count
{
public:
    shared_count() noexcept
        : count_(1) {}
    void add_count() noexcept
    {
        ++count_;
    }
    long reduce_count() noexcept
    {
        return --count_;
    }
    long get_count() const noexcept
    {
        return count_;
    }

private:
    long count_;
};

template <typename T>
class smart_ptr
{
private:
    T *ptr_;
    shared_count *shared_count_;

public:
    template <typename U>
    friend class smart_ptr; // 注:模板的各个实例间并不天然就有 friend 关系，因而不能互访私有成员 ptr_ 和 shared_count_

    explicit smart_ptr(T *ptr = nullptr) // 注:explicit防止隐式类型转换
        : ptr_(ptr)
    {
        if (ptr)
            shared_count_ = new shared_count();
    }
    ~smart_ptr()
    {
        printf("~smart_ptr(): %p\n", this);
        if (ptr_ && !shared_count_->reduce_count())
        {
            delete ptr_;
            delete shared_count_;
        }
    }
    template <typename U>                         // 注:拷贝和移动这里，使用模板是为了实现子类指针隐式转换为父类指针：smart_ptr<Derived> -> smart_ptr<Base>
    smart_ptr(const smart_ptr<U> &other) noexcept // 拷贝
    {
        ptr_ = other.ptr_;
        if (ptr_)
        {
            other.shared_count_->add_count();
            shared_count_ = other.shared_count_;
        }
    }
    template <typename U>
    smart_ptr(smart_ptr<U> &&other) noexcept // 移动
    {
        ptr_ = other.ptr_;
        if (ptr_)
        {
            shared_count_ = other.shared_count_;
            other.ptr_ = nullptr;
        }
    }
    template <typename U>
    smart_ptr(const smart_ptr<U> &other, T *ptr) noexcept // 注:这个构造函数主要用于四个类型转换函数
    {
        ptr_ = ptr;
        if (ptr_)
        {
            other.shared_count_->add_count();
            shared_count_ = other.shared_count_;
        }
    }
    smart_ptr &operator=(smart_ptr rhs) noexcept // 赋值
    {
        // 注:赋值的流程：
        // 1.先调用拷贝/移动(具体是拷贝还是移动，看rhs是左值还是右值)得到rhs
        // 2.然后用swap获取rhs的资源
        // 阅读:What is the copy-and-swap idiom? https://stackoverflow.com/a/3279550/816999

        rhs.swap(*this);
        return *this;
    }

    T *get() const noexcept
    {
        return ptr_;
    }
    long use_count() const noexcept
    {
        if (ptr_)
            return shared_count_->get_count();
        else
            return 0;
    }
    void swap(smart_ptr &rhs) noexcept
    {
        std::swap(ptr_, rhs.ptr_);
        std::swap(shared_count_, rhs.shared_count_);
    }
    T &operator*() const noexcept
    {
        return *ptr_;
    }
    T *operator->() const noexcept
    {
        return ptr_;
    }
    operator bool() const noexcept
    {
        return ptr_;
    }
};

template <typename T>
void swap(smart_ptr<T> &lhs, smart_ptr<T> &rhs) noexcept
{
    lhs.swap(rhs);
}

template <typename T, typename U>
smart_ptr<T> static_pointer_cast(const smart_ptr<U> &other) noexcept
{
    T *ptr = static_cast<T *>(other.get());
    return smart_ptr<T>(other, ptr);
}
template <typename T, typename U>
smart_ptr<T> reinterpret_pointer_cast(const smart_ptr<U> &other) noexcept
{
    T *ptr = reinterpret_cast<T *>(other.get());
    return smart_ptr<T>(other, ptr);
}
template <typename T, typename U>
smart_ptr<T> const_pointer_cast(const smart_ptr<U> &other) noexcept
{
    T *ptr = const_cast<T *>(other.get());
    return smart_ptr<T>(other, ptr);
}
template <typename T, typename U>
smart_ptr<T> dynamic_pointer_cast(const smart_ptr<U> &other) noexcept
{
    T *ptr = dynamic_cast<T *>(other.get());
    return smart_ptr<T>(other, ptr);
}

class Base
{
public:
    virtual void show() const
    {
        std::cout << "Base class" << std::endl;
    }
    virtual ~Base() = default;
};

class Derived : public Base
{
public:
    void show() const override
    {
        std::cout << "Derived class" << std::endl;
    }
};

int main()
{
    // 创建 smart_ptr<Base> 对象
    smart_ptr<Base> basePtr(new Base());
    std::cout << "Base pointer use count: " << basePtr.use_count() << std::endl;
    basePtr->show();

    // 创建 smart_ptr<Derived> 对象并共享 basePtr 的引用计数
    smart_ptr<Derived> derivedPtr(basePtr, new Derived());
    std::cout << "Base pointer use count after creating derivedPtr: " << basePtr.use_count() << std::endl;
    std::cout << "Derived pointer use count: " << derivedPtr.use_count() << std::endl;
    derivedPtr->show();

    return 0;
}